<% include include/header.html %>  
<style>

  .axis path,
  .axis line{
    fill: none;
    stroke: black;
    shape-rendering: crispEdges;
  }

  .axis text {
    font-family: sans-serif;
    font-size: 11px;
  }

  .MyRect {
    /*fill: steelblue;*/
  }

  .MyText {
    fill: white;
    text-anchor: middle;
  }

</style>
  <!-- Content Wrapper. Contains page content -->
  <div class="content-wrapper">
    <!-- Content Header (Page header) -->
    <section class="content-header">
      <h1>
        力导向图
        <small>网络拓扑</small>
      </h1>
      <ol class="breadcrumb">
        <li><a href="#"><i class="fa fa-dashboard"></i> Home</a></li>
        <li class="active">Dashboard</li>
      </ol>
    </section>

    <!-- Main content -->
    <section class="content dashboard-page">

    </section>
    <!-- /.content -->
  </div>
<script src="bower_components/d3/d3.js"></script>
<script>
//https://observablehq.com/@d3/force-directed-graph
//https://blog.csdn.net/wanglei1991gao/article/details/79551724

var imgMap = {
  'gateway':'image/cloud-province.png',
  'device':'image/cloud-city.png',
  '2':'image/cloud-county.png',
  'error-tip':'image/error-tip.png',
  'link-cut':'image/link-cut.png'
};
var data = {
}

var response = {"status":"success","data":{"id":15,"createTime":"2019-04-12T05:46:53.000+0000","updateTime":"2019-04-12T05:46:53.000+0000","code":"GW_97LLJB21CUX","name":"性能测试网关-那-10","physicalConnType":"SOCKET","config":"{\"ipAddress\":\"10.1.5.123\",\"port\":510}","workMode":"PULL","connectTimeout":1,"connectRetry":0,"disabled":true,"resourceSize":10,"resources":[{"id":91,"createTime":"2019-04-12T05:54:42.000+0000","updateTime":"2019-04-12T05:54:42.000+0000","code":"RS_97LLJEC9SPV","name":"那-Slave-10-9","disabled":false,"config":"{\"slave\":\"9\"}","gatewayCode":"GW_97LLJB21CUX","type":"0049","gateway":{"id":15,"createTime":"2019-04-12T05:46:53.000+0000","updateTime":"2019-04-12T05:46:53.000+0000","code":"GW_97LLJB21CUX","name":"性能测试网关-那-10","physicalConnType":"SOCKET","config":"{\"ipAddress\":\"10.1.5.123\",\"port\":510}","workMode":"PULL","connectTimeout":1,"connectRetry":0,"disabled":true,"resourceSize":10,"resources":[]},"metricGroupSize":1,"metricGroups":[{"id":1,"createTime":"2019-04-12T05:31:53.000+0000","updateTime":"2019-04-12T05:32:25.000+0000","code":"MG_97LLJ9A5YPB","name":"性能测试-MODBUS-300指标-可合并","protocol":"MODBUS_TCP","config":null,"executionCycle":20,"usageType":"COLLECT","metricSize":300,"metrics":[]}]},{"id":92,"createTime":"2019-04-12T05:54:42.000+0000","updateTime":"2019-04-12T05:54:42.000+0000","code":"RS_97LLJEC9SPW","name":"那-Slave-10-6","disabled":false,"config":"{\"slave\":\"6\"}","gatewayCode":"GW_97LLJB21CUX","type":"0049","gateway":{"id":15,"createTime":"2019-04-12T05:46:53.000+0000","updateTime":"2019-04-12T05:46:53.000+0000","code":"GW_97LLJB21CUX","name":"性能测试网关-那-10","physicalConnType":"SOCKET","config":"{\"ipAddress\":\"10.1.5.123\",\"port\":510}","workMode":"PULL","connectTimeout":1,"connectRetry":0,"disabled":true,"resourceSize":10,"resources":[]},"metricGroupSize":1,"metricGroups":[{"id":1,"createTime":"2019-04-12T05:31:53.000+0000","updateTime":"2019-04-12T05:32:25.000+0000","code":"MG_97LLJ9A5YPB","name":"性能测试-MODBUS-300指标-可合并","protocol":"MODBUS_TCP","config":null,"executionCycle":20,"usageType":"COLLECT","metricSize":300,"metrics":[]}]},{"id":93,"createTime":"2019-04-12T05:54:42.000+0000","updateTime":"2019-04-12T05:54:42.000+0000","code":"RS_97LLJEC9SPX","name":"那-Slave-10-4","disabled":false,"config":"{\"slave\":\"4\"}","gatewayCode":"GW_97LLJB21CUX","type":"0049","gateway":{"id":15,"createTime":"2019-04-12T05:46:53.000+0000","updateTime":"2019-04-12T05:46:53.000+0000","code":"GW_97LLJB21CUX","name":"性能测试网关-那-10","physicalConnType":"SOCKET","config":"{\"ipAddress\":\"10.1.5.123\",\"port\":510}","workMode":"PULL","connectTimeout":1,"connectRetry":0,"disabled":true,"resourceSize":10,"resources":[]},"metricGroupSize":1,"metricGroups":[{"id":1,"createTime":"2019-04-12T05:31:53.000+0000","updateTime":"2019-04-12T05:32:25.000+0000","code":"MG_97LLJ9A5YPB","name":"性能测试-MODBUS-300指标-可合并","protocol":"MODBUS_TCP","config":null,"executionCycle":20,"usageType":"COLLECT","metricSize":300,"metrics":[]}]},{"id":94,"createTime":"2019-04-12T05:54:42.000+0000","updateTime":"2019-04-12T05:54:42.000+0000","code":"RS_97LLJEC9SPY","name":"那-Slave-10-3","disabled":false,"config":"{\"slave\":\"3\"}","gatewayCode":"GW_97LLJB21CUX","type":"0049","gateway":{"id":15,"createTime":"2019-04-12T05:46:53.000+0000","updateTime":"2019-04-12T05:46:53.000+0000","code":"GW_97LLJB21CUX","name":"性能测试网关-那-10","physicalConnType":"SOCKET","config":"{\"ipAddress\":\"10.1.5.123\",\"port\":510}","workMode":"PULL","connectTimeout":1,"connectRetry":0,"disabled":true,"resourceSize":10,"resources":[]},"metricGroupSize":1,"metricGroups":[{"id":1,"createTime":"2019-04-12T05:31:53.000+0000","updateTime":"2019-04-12T05:32:25.000+0000","code":"MG_97LLJ9A5YPB","name":"性能测试-MODBUS-300指标-可合并","protocol":"MODBUS_TCP","config":null,"executionCycle":20,"usageType":"COLLECT","metricSize":300,"metrics":[]}]},{"id":95,"createTime":"2019-04-12T05:54:42.000+0000","updateTime":"2019-04-12T05:54:42.000+0000","code":"RS_97LLJEC9SPZ","name":"那-Slave-10-2","disabled":false,"config":"{\"slave\":\"2\"}","gatewayCode":"GW_97LLJB21CUX","type":"0049","gateway":{"id":15,"createTime":"2019-04-12T05:46:53.000+0000","updateTime":"2019-04-12T05:46:53.000+0000","code":"GW_97LLJB21CUX","name":"性能测试网关-那-10","physicalConnType":"SOCKET","config":"{\"ipAddress\":\"10.1.5.123\",\"port\":510}","workMode":"PULL","connectTimeout":1,"connectRetry":0,"disabled":true,"resourceSize":10,"resources":[]},"metricGroupSize":1,"metricGroups":[{"id":1,"createTime":"2019-04-12T05:31:53.000+0000","updateTime":"2019-04-12T05:32:25.000+0000","code":"MG_97LLJ9A5YPB","name":"性能测试-MODBUS-300指标-可合并","protocol":"MODBUS_TCP","config":null,"executionCycle":20,"usageType":"COLLECT","metricSize":300,"metrics":[]}]},{"id":96,"createTime":"2019-04-12T05:54:42.000+0000","updateTime":"2019-04-12T05:54:42.000+0000","code":"RS_97LLJEC9SP0","name":"那-Slave-10-1","disabled":false,"config":"{\"slave\":\"1\"}","gatewayCode":"GW_97LLJB21CUX","type":"0049","gateway":{"id":15,"createTime":"2019-04-12T05:46:53.000+0000","updateTime":"2019-04-12T05:46:53.000+0000","code":"GW_97LLJB21CUX","name":"性能测试网关-那-10","physicalConnType":"SOCKET","config":"{\"ipAddress\":\"10.1.5.123\",\"port\":510}","workMode":"PULL","connectTimeout":1,"connectRetry":0,"disabled":true,"resourceSize":10,"resources":[]},"metricGroupSize":1,"metricGroups":[{"id":1,"createTime":"2019-04-12T05:31:53.000+0000","updateTime":"2019-04-12T05:32:25.000+0000","code":"MG_97LLJ9A5YPB","name":"性能测试-MODBUS-300指标-可合并","protocol":"MODBUS_TCP","config":null,"executionCycle":20,"usageType":"COLLECT","metricSize":300,"metrics":[]}]},{"id":97,"createTime":"2019-04-12T05:54:42.000+0000","updateTime":"2019-04-12T05:54:42.000+0000","code":"RS_97LLJEC9SQ1","name":"那-Slave-10-10","disabled":false,"config":"{\"slave\":\"10\"}","gatewayCode":"GW_97LLJB21CUX","type":"0049","gateway":{"id":15,"createTime":"2019-04-12T05:46:53.000+0000","updateTime":"2019-04-12T05:46:53.000+0000","code":"GW_97LLJB21CUX","name":"性能测试网关-那-10","physicalConnType":"SOCKET","config":"{\"ipAddress\":\"10.1.5.123\",\"port\":510}","workMode":"PULL","connectTimeout":1,"connectRetry":0,"disabled":true,"resourceSize":10,"resources":[]},"metricGroupSize":1,"metricGroups":[{"id":1,"createTime":"2019-04-12T05:31:53.000+0000","updateTime":"2019-04-12T05:32:25.000+0000","code":"MG_97LLJ9A5YPB","name":"性能测试-MODBUS-300指标-可合并","protocol":"MODBUS_TCP","config":null,"executionCycle":20,"usageType":"COLLECT","metricSize":300,"metrics":[]}]},{"id":98,"createTime":"2019-04-12T05:54:42.000+0000","updateTime":"2019-04-12T05:54:42.000+0000","code":"RS_97LLJEC9SQ2","name":"那-Slave-10-8","disabled":false,"config":"{\"slave\":\"8\"}","gatewayCode":"GW_97LLJB21CUX","type":"0049","gateway":{"id":15,"createTime":"2019-04-12T05:46:53.000+0000","updateTime":"2019-04-12T05:46:53.000+0000","code":"GW_97LLJB21CUX","name":"性能测试网关-那-10","physicalConnType":"SOCKET","config":"{\"ipAddress\":\"10.1.5.123\",\"port\":510}","workMode":"PULL","connectTimeout":1,"connectRetry":0,"disabled":true,"resourceSize":10,"resources":[]},"metricGroupSize":1,"metricGroups":[{"id":1,"createTime":"2019-04-12T05:31:53.000+0000","updateTime":"2019-04-12T05:32:25.000+0000","code":"MG_97LLJ9A5YPB","name":"性能测试-MODBUS-300指标-可合并","protocol":"MODBUS_TCP","config":null,"executionCycle":20,"usageType":"COLLECT","metricSize":300,"metrics":[]}]},{"id":99,"createTime":"2019-04-12T05:54:42.000+0000","updateTime":"2019-04-12T05:54:42.000+0000","code":"RS_97LLJEC9SQ3","name":"那-Slave-10-7","disabled":false,"config":"{\"slave\":\"7\"}","gatewayCode":"GW_97LLJB21CUX","type":"0049","gateway":{"id":15,"createTime":"2019-04-12T05:46:53.000+0000","updateTime":"2019-04-12T05:46:53.000+0000","code":"GW_97LLJB21CUX","name":"性能测试网关-那-10","physicalConnType":"SOCKET","config":"{\"ipAddress\":\"10.1.5.123\",\"port\":510}","workMode":"PULL","connectTimeout":1,"connectRetry":0,"disabled":true,"resourceSize":10,"resources":[]},"metricGroupSize":1,"metricGroups":[{"id":1,"createTime":"2019-04-12T05:31:53.000+0000","updateTime":"2019-04-12T05:32:25.000+0000","code":"MG_97LLJ9A5YPB","name":"性能测试-MODBUS-300指标-可合并","protocol":"MODBUS_TCP","config":null,"executionCycle":20,"usageType":"COLLECT","metricSize":300,"metrics":[]}]},{"id":100,"createTime":"2019-04-12T05:54:42.000+0000","updateTime":"2019-04-12T05:54:42.000+0000","code":"RS_97LLJEC9SQ4","name":"那-Slave-10-5","disabled":false,"config":"{\"slave\":\"5\"}","gatewayCode":"GW_97LLJB21CUX","type":"0049","gateway":{"id":15,"createTime":"2019-04-12T05:46:53.000+0000","updateTime":"2019-04-12T05:46:53.000+0000","code":"GW_97LLJB21CUX","name":"性能测试网关-那-10","physicalConnType":"SOCKET","config":"{\"ipAddress\":\"10.1.5.123\",\"port\":510}","workMode":"PULL","connectTimeout":1,"connectRetry":0,"disabled":true,"resourceSize":10,"resources":[]},"metricGroupSize":1,"metricGroups":[{"id":1,"createTime":"2019-04-12T05:31:53.000+0000","updateTime":"2019-04-12T05:32:25.000+0000","code":"MG_97LLJ9A5YPB","name":"性能测试-MODBUS-300指标-可合并","protocol":"MODBUS_TCP","config":null,"executionCycle":20,"usageType":"COLLECT","metricSize":300,"metrics":[]}]}]}};
let gatewayNode = {
  type: 'gateway',
  code: response.data.code,
  name: response.data.name,
}
let deviceNodes = response.data.resources.map( r => {
  return {
    type: 'device',
    code: r.code,
    name: r.name,
  }
})
data.nodes = [gatewayNode, ...deviceNodes]
data.links = response.data.resources.map( r => {
  return {
    source: response.data.code,
    target: r.code,
  }
})

console.log(data)


drag = simulation => {
  
  function dragstarted(d) {
    if (!d3.event.active) simulation.alphaTarget(0.3).restart();
    d.fx = d.x;
    d.fy = d.y;
  }
  
  function dragged(d) {
    d.fx = d3.event.x;
    d.fy = d3.event.y;
  }
  
  function dragended(d) {
    if (!d3.event.active) simulation.alphaTarget(0);
    d.fx = null;
    d.fy = null;
  }
  
  return d3.drag()
      .on("start", dragstarted)
      .on("drag", dragged)
      .on("end", dragended);
}

color = () => {
  const scale = d3.scaleOrdinal(d3.schemeCategory10);
  return d => scale(d.group);
}
let height = 600, width = 800, nodeBaseWidth = 40, nodeBaseHeight = 40;
// let promise = d3.json("https://gist.githubusercontent.com/mbostock/4062045/raw/5916d145c8c048a6e3086915a6be464467391c62/miserables.json")
// promise.then(data => {
//   chart(data)
// })

chart = (data) => {
  const links = data.links.map(d => Object.create(d));
  const nodes = data.nodes.map(d => Object.create(d));

  const simulation = d3.forceSimulation(nodes)
      .force("link", d3.forceLink(links).id(d => d.code).distance(d=> 200))
      .force("charge", d3.forceManyBody())
      .force("center", d3.forceCenter(width / 2, height / 2));

  const svg = d3.select('.dashboard-page')
      .append('svg')
      .attr('width', width)
      .attr('height', height);

  const link = svg.append("g")
      .attr("stroke", "#ffff00")
      .attr("stroke-opacity", 0.6)
      .selectAll("line")
      .data(links)
      .join("line")
      .style('stroke',function(d){
          if(d.index % 2 == 0){
            return '#f76e5d';
          }else{
            return '#93c62d';
          }
        })
      .attr("stroke-width", d => Math.sqrt(d.value));

  const _g_nodes = svg.append("g")
      .attr('class', 'g-node')
      .attr("stroke", "#fff")
      .attr("stroke-width", 1.5)
      .selectAll("image")
      .data(nodes)
      .join("image")
      .style("width",function(d){
        var width = nodeBaseWidth;
        if(d.type == 'gateway') {
          width = 1.5 * width;
        } else if(d.type == 'device') {
          width = 0.8 * width;
        }
        return width;
      })
      .style("height",function(d){
          var height = nodeBaseHeight;
          if(d.type == 'gateway') {
            height = 1.5 * height;
          } else if(d.type == 'device') {
            height = 0.8 * height;
          }
          return height;
      })
      .attr("href",function(d){
        return imgMap[d.type];
      })
      .call(drag(simulation));

  const _g_texts = svg.select("g.g-node")
      .selectAll("text")
      .data(nodes)
      .join("text")
      .attr("stroke", "#999")
      .attr("stroke-width", 1)
      .text(d => d.name);

  simulation.on("tick", () => {
    link
        .attr("x1", d => d.source.x)
        .attr("y1", d => d.source.y)
        .attr("x2", d => d.target.x)
        .attr("y2", d => d.target.y);

    _g_nodes
        .attr("x", d => {
          let offset = 0;
          if(d.type == 'gateway') {
            offset = 1.5 * nodeBaseWidth / 2;
          } else if(d.type == 'device') {
            offset = 0.8 * nodeBaseWidth / 2;
          }
          console.log(d.x - offset)
          return d.x - offset
        })
        .attr("y", d => {
          let offset = 0;
          if(d.type == 'gateway') {
            offset = 1.5 * nodeBaseHeight / 2;
          } else if(d.type == 'device') {
            offset = 0.8 * nodeBaseHeight / 2;
          }
          return d.y - offset
        });

    _g_texts
        .attr("x", d => {
          let offset = 0;
          if(d.type == 'gateway') {
            offset = 1.5 * nodeBaseWidth / 2;
          } else if(d.type == 'device') {
            offset = 0.8 * nodeBaseWidth / 2;
          }
          return d.x + offset + 10
        })
        .attr("y", d => d.y);
  });

  //invalidation.then(() => simulation.stop());

  return svg.node();
}

chart(data)

</script>
<% include include/footer.html %>